/**
 *  Copyright © 2019 eSunny Info. Tech Ltd. All rights reserved.
 *
 *  @Package: com.svimer.core.aspect 
 *  @ClassName: SvimerAspect 
 *  @Description: TODO
 *  @author: Svimer 
 *  @date: 2019年9月8日 下午9:33:05 
 */
package com.svimer.core.aspect;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.svimer.core.model.Context;
import com.svimer.core.template.ChannelTemplate;

/**
 * AOP注解说明：
 * 
 * @Aspect 定义切面：切面由切点和增强（引介）组成(可以包含多个切点和多个增强)，它既包括了横切逻辑的定义，也包括了连接点的定义，SpringAOP就是负责实施切面的框架，它将切面所定义的横切逻辑织入到切面所指定的链接点中。
 * @Pointcut 定义切点：切点是一组连接点的集合。AOP通过“切点”定位特定的连接点。通过数据库查询的概念来理解切点和连接点的关系再适合不过了：连接点相当于数据库中的记录，而切点相当于查询条件。
 * @Before ：在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可。
 * @AfterReturning ：
 *                 在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后，还可以指定一个返回值形参名returning,代表目标方法的返回值。 @Afterthrowing：
 *                 主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后，还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象。 @After：
 *                 在目标方法完成之后做增强，无论目标方法时候成功完成。@After可以指定一个切入点表达式。 @Around：
 *                 环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint。
 *
 */
@Aspect
@Component
public class SvimerAspect {

	private static final Logger LOG = LoggerFactory.getLogger(SvimerAspect.class);

	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void advice() {
	}

	@Before("advice()")
	public void before(JoinPoint joinPoint) {

		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		//

		//

		// Method
//		LOG.warn("Method={}", request.getMethod());

		//
		// Class.Method
//		String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()
//				+ "()";
//		LOG.warn("CLass.Method={}", classMethod);
		//
		//
		//
		//
		// Args
//		Object[] args = joinPoint.getArgs();
//		LOG.warn("Args={}", args);
		//
		// //...其余操作

	}

	@Around("advice()")
	public Object around(ProceedingJoinPoint pj) throws Throwable {
		// LOG.warn("环绕通知进入方法");
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();

		// --------------------------trans参数------------------------------------------
		// 修改请求参数
		Map<String, String[]> parameterMap = request.getParameterMap();
		// 将请求参数存入context中
		Context context = new Context();
		context.setAllDate(parameterMap);
		// 将context放在切点中
		Object[] args = pj.getArgs();
		args[0] = context;
		// --------------------------trans日志开始------------------------------------------
		String logParam = ChannelTemplate.getLogParam(request);
		
		LOG.info("trans start: "+logParam);
		// 获取交易执行结果
		Object object = pj.proceed(args);

		// --------------------------trans日志结束------------------------------------------
		LOG.info("trans end: "+logParam);
		return object;
	}

	@After("advice()")
	public void after() {
		// LOG.warn("最终通知");
	}

	@AfterThrowing(pointcut = "advice()", throwing = "ex")
	public void afterThrowing(Throwable ex) {
		// LOG.warn("例外通知:"+ex);
	}

	@AfterReturning(pointcut = "advice()", returning = "result")
	public void afterReturning(Object result) {
		// LOG.warn("后置通知:"+result);

	}

}
